import { PluginOption } from 'vite'
import fs from 'fs'
import path from 'path'
import { App, ref, getCurrentInstance, inject, Ref } from 'vue'

// 插件读取文件json 插件选项劫持 message 请求
// 或者读模块 ？vue type=i18n
// app.use 注册 派发数据
// useI18n() sfc中导出方法 供模板使用

// 模块内引用
// transfrom改代码块
// 保存到实例上，在实例上读数据

// 全局文件引入，局部模板都可以用，局部优先
export interface MyI18nOptions {
  include?: string[] | string
}

export type Source = { [key: string]: { [key: string]: string } }

// plugin for vite
export default function (options: MyI18nOptions): PluginOption {
  const IMPORT_ID = 'MyI18n/message'
  let include = options.include

  return {
    name: 'my-vue-i18n',
    resolveId (id: string) {
      if (id === IMPORT_ID) {
        return id
      }
    },
    async load (id: string) {
      if (id === IMPORT_ID && include) {
        const data = getSource(include)
        if (Object.keys(data).length === 0) console.warn(`Check whether there is 'message' delivered to myI18n`)
        console.log(data)
        return `export default ${JSON.stringify(data)}`
      }
    },
    transform (code, id) {
      const isI18n = id.includes('?vue&type=my-i18n')
      if (isI18n) {
        return `export default Comp => {
            Comp.__myI18n = ${code}
          }`
      }
    }
  }

  function getSource (include: string[] | string): Source {
    let allPath = [] as string[]
    const data: Source = {}

    if (Array.isArray(include)) {
      const path = include.map(getAbsPath)
      allPath = allPath.concat(path)
    } else if (typeof include === 'string') {
      allPath.push(getAbsPath(include))
    }

    allPath.forEach(dirPath => {
      let lists: string[]

      try {
        lists = fs.readdirSync(dirPath)
      } catch (error) {
        throw new Error(`failed to resolve path\n${error}`)
      }

      lists
        .filter(fileName => fileName.includes('.json'))
        .forEach(fileName => {
          const category = fileName.replace('.json', '')
          const source = require(path.join(dirPath, fileName)) as Source
          const cateObj = data[category] = data[category] ?? {}
          Object.assign(cateObj, source)
        })
    })

    return data
  }

  function getAbsPath (pathx: string): string {
    return isAbsPath(pathx) ? pathx : path.join(process.cwd(), pathx)
  }

  function isAbsPath (path: string): boolean {
    return path.includes(':')
  }
}

// app.use
export interface Options {
  source: Source
  locale: string
}
export interface ProvideData {
  source: Source
  locale: Ref<string>
}
export function myI18n (app: App, { locale: defalutLocale, source }: Options): void {
  if (source && defalutLocale) {
    const locale = ref(defalutLocale)
    app.provide('myI18n', { locale, source })
  }
}

// use in component
export function useMyI18n (): { t: (key: string) => string, locale: Ref<string> } {
  const ins = getCurrentInstance()
  // 全局注册的 source
  const { source, locale } = inject('myI18n') as ProvideData

  const t = (key: string) => {
    return (ins?.type as any)?.__myI18n?.[locale.value][key] ?? (source[locale.value] as any)[key] ?? ''
  }
  return { t, locale }
}
